﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.IO;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using MigracionAga.Properties;
using System.Data.OleDb;

namespace MigracionAga
{
    class Program
    {
        static void Main(string[] args)
        {
            var worker = new Migrador();

            worker.Run();

            Console.WriteLine("Presione cualquier tecla para terminar...");
            Console.ReadKey();
        }
    }

    public class Migrador
    {
        FileStream logFile;
        StreamWriter logger;

        List<Cliente> clientes = new List<Cliente>();
        List<CajaDeCliente> cajas = new List<CajaDeCliente>();
        List<Deposito> depositos = new List<Deposito>();
        List<Estanteria> estanterias = new List<Estanteria>();
        List<Ubicacion> ubicaciones = new List<Ubicacion>();

        List<ErroresEnClientes> erroresClientes = new List<ErroresEnClientes>();
        List<ErroresEnCajasDeClientes> erroresCajasDeClientes = new List<ErroresEnCajasDeClientes>();
        List<ErroresEnDepositos> erroresDepositos = new List<ErroresEnDepositos>();
        List<ErroresEnEstanterias> erroresEstanterias = new List<ErroresEnEstanterias>();
        List<ErroresEnUbicaciones> erroresUbicaciones = new List<ErroresEnUbicaciones>();

        public void Run()
        {
            Console.WriteLine("Iniciando migración de datos...");

            var logName = String.Format("Log.{0}.csv", DateTime.Now.ToString("yyyyMMdd"));
            logFile = new FileStream(logName, FileMode.Create);
            logger = new StreamWriter(logFile);

            try
            {
                //LeerClientes();
                LeerCajasDeClientes();
                //LeerDepositos();
                //LeerEstanterias();
                LeerUbicaciones();

                using (var conn = new SqlConnection(Settings.Default.SQLConnectionString))
                {
                    conn.Open();

                    //LimpiarTablas(conn);

                    //CargarClientes(conn);
                    //CargarCajasDeClientes(conn);
                    //CargarDepositos(conn);
                    //CargarEstanterias(conn);
                    CargarUbicaciones(conn);

                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }

                InformarCajasSinUbicar();

                LogErrors();
            }
            catch (Exception ex)
            {
                while (ex != null)
                {
                    Console.WriteLine(ex.Message);
                    ex = ex.InnerException;
                }

                Console.WriteLine("\nMigración abortada.\n");
            }
            finally
            {
                logger.Close();
            }
        }

        // INSERTS

        private void LeerClientes()
        {
            using (var conn = new OleDbConnection(Settings.Default.agaConnectionString))
            {
                var cmd = conn.CreateCommand();

                cmd.CommandText = "SELECT * FROM Clientes";

                Log("Leyendo Clientes...", true);

                conn.Open();

                var reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    var cliente = new Cliente();

                    cliente.codigo = reader.GetInt32(0);
                    cliente.nombre = reader.IsDBNull(1) ? string.Empty : reader.GetString(1);
                    cliente.responsable = reader.IsDBNull(2) ? string.Empty : reader.GetString(2);
                    cliente.emailResponsable = reader.IsDBNull(3) ? string.Empty : reader.GetString(3);
                    cliente.telefonos = reader.IsDBNull(4) ? string.Empty : reader.GetString(4);
                    cliente.fax = reader.IsDBNull(5) ? string.Empty : reader.GetString(5);
                    cliente.direccion = reader.IsDBNull(6) ? string.Empty : reader.GetString(6);
                    cliente.cp = reader.IsDBNull(7) ? string.Empty : reader.GetString(7);
                    cliente.localidad = reader.IsDBNull(8) ? string.Empty : reader.GetString(8);
                    cliente.provincia = reader.IsDBNull(9) ? string.Empty : reader.GetString(9);
                    cliente.cuit = reader.IsDBNull(13) ? string.Empty : reader.GetString(13);
                    cliente.web = reader.IsDBNull(14) ? string.Empty : reader.GetString(14);
                    cliente.email1 = reader.IsDBNull(15) ? string.Empty : reader.GetString(15);
                    cliente.email2 = reader.IsDBNull(16) ? string.Empty : reader.GetString(16);

                    clientes.Add(cliente);
                }

                if (conn.State == ConnectionState.Open)
                    conn.Close();

                Log(String.Format("Se han leído {0} clientes.", clientes.Count), true);
            }
        }

        private void LeerCajasDeClientes()
        {
            using (var conn = new OleDbConnection(Settings.Default.agaConnectionString))
            {
                var cmd = conn.CreateCommand();

                cmd.CommandText = "SELECT * FROM CajasClientes";

                conn.Open();

                var reader = cmd.ExecuteReader();

                Log("Leyendo Cajas de Clientes...", true);

                while (reader.Read())
                {
                    var caja = new CajaDeCliente();

                    caja.clienteId = reader.GetInt32(0);
                    caja.numero = reader.IsDBNull(1) ? 0 : reader.GetInt32(1);
                    caja.codigoBarra = reader.IsDBNull(2) ? string.Empty : reader.GetString(2);
                    caja.numeroUbicacion = reader.IsDBNull(3) ? new Nullable<int>() : reader.GetInt32(3);
                    caja.ubicacionId = new Nullable<int>();
                    caja.observaciones = reader.IsDBNull(4) ? null : reader.GetString(4);

                    cajas.Add(caja);
                }

                if (conn.State == ConnectionState.Open)
                    conn.Close();
            }

            Log(String.Format("Se han leído {0} cajas de clientes.", cajas.Count), true);
        }

        private void LeerDepositos()
        {
            using (var conn = new OleDbConnection(Settings.Default.agaConnectionString))
            {
                var cmd = conn.CreateCommand();

                cmd.CommandText = "SELECT * FROM Deposito";

                conn.Open();

                var reader = cmd.ExecuteReader();

                Log("Leyendo Depósitos...", true);

                while (reader.Read())
                {
                    var deposito = new Deposito();

                    deposito.id = reader.GetInt32(0);
                    deposito.numero = reader.IsDBNull(1) ? 0 : reader.GetInt32(1);
                    deposito.nombre = reader.IsDBNull(2) ? string.Empty : reader.GetString(2);
                    deposito.descripcion = reader.IsDBNull(3) ? string.Empty : reader.GetString(3);

                    depositos.Add(deposito);
                }
                if (conn.State == ConnectionState.Open)
                    conn.Close();
            }

            Log(String.Format("Se han leído {0} depositos.", depositos.Count), true);
        }

        private void LeerEstanterias()
        {
            using (var conn = new OleDbConnection(Settings.Default.agaConnectionString))
            {
                var cmd = conn.CreateCommand();

                cmd.CommandText = "SELECT * FROM Estanteria";

                conn.Open();

                var reader = cmd.ExecuteReader();

                Log("Leyendo Estanterías...", true);

                while (reader.Read())
                {
                    var estanteria = new Estanteria();

                    estanteria.id = reader.GetInt32(0);
                    estanteria.depositoId = reader.GetInt32(1);
                    estanteria.numero = reader.GetInt32(2);
                    estanteria.sector = reader.GetInt32(3);
                    estanteria.horizontal = reader.GetInt32(4);
                    estanteria.vertical = reader.GetInt32(5);
                    estanteria.fondo = reader.GetInt32(6);

                    estanterias.Add(estanteria);
                }

                if (conn.State == ConnectionState.Open)
                    conn.Close();
            }

            Log(String.Format("Se han leído {0} estanterias.", estanterias.Count), true);
        }

        private void LeerUbicaciones()
        {
            using (var conn = new OleDbConnection(Settings.Default.agaConnectionString))
            {
                var cmd = conn.CreateCommand();

                cmd.CommandText = "SELECT * FROM Ubicaciones";

                conn.Open();

                var reader = cmd.ExecuteReader();

                Log("Leyendo Ubicaciones...", true);

                while (reader.Read())
                {
                    var ubicacion = new Ubicacion();

                    try
                    {
                        ubicacion.numeroCaja = reader.GetInt32(1);
                        ubicacion.estanteriaId = reader.GetInt32(3);
                        ubicacion.sector = reader.GetInt32(4);
                        ubicacion.cuadrante = reader.GetInt32(5);
                        ubicacion.vertical = reader.GetInt32(6);
                        ubicacion.horizontal = reader.GetInt32(7);
                        ubicacion.fondo = reader.GetInt32(8);
                        ubicacion.codigoBarraCajaCliente = reader.IsDBNull(9) ? null : reader.GetString(9);
                        ubicacion.estado = reader.IsDBNull(11) ? string.Empty : reader.GetString(11);
                        ubicacion.codigoBarra = reader.GetString(12);
                    }
                    catch (Exception)
                    {
                        throw;
                    }


                    ubicaciones.Add(ubicacion);
                }

                if (conn.State == ConnectionState.Open)
                    conn.Close();
            }

            Log(String.Format("Se han leído {0} ubicaciones.", ubicaciones.Count), true);

        }

        // CARGA

        //private void LimpiarTablas(SqlConnection conn)
        //{
        //    Log("Limpiando tablas...", true);

        //    // borro todo
        //    var cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM ItemsRemito";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Remitos";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Movimientos";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM CajasClientes";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Ubicaciones";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Estanterias";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Depositos";
        //    cmd.ExecuteNonQuery();

        //    cmd = conn.CreateCommand();
        //    cmd.CommandText = "DELETE FROM Clientes";
        //    cmd.ExecuteNonQuery();
        //}

        private void CargarClientes(SqlConnection conn)
        {
            Log("Insertando Clientes...", true);

            var cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Clientes ON";
            cmd.ExecuteNonQuery();

            int count = 0;
            foreach (var cliente in clientes)
            {
                try
                {
                    cmd.CommandText = "SELECT COUNT(*) FROM Clientes WHERE Id = " + cliente.codigo;
                    int cnt = (int)cmd.ExecuteScalar();
                    if (cnt != 0)
                        continue;

                    cmd = conn.CreateCommand();
                    cmd.CommandText = GetClienteInsert(cliente);
                    cmd.ExecuteNonQuery();

                    count++;
                }
                catch (Exception ex)
                {
                    erroresClientes.Add(new ErroresEnClientes
                    {
                        cliente = cliente,
                        exception = ex
                    });
                }
            }

            Log(String.Format("Se insertaron {0} clientes de {1}. {2} Errores.", count, clientes.Count, erroresClientes.Count), true);

            cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Clientes OFF";
            cmd.ExecuteNonQuery();

        }

        private void CargarCajasDeClientes(SqlConnection conn)
        {
            Log("Insertando Cajas de Clientes...", true);

            int partial = 200;
            int count = 0;
            int success = 0;
            foreach (var caja in cajas)
            {
                count++;
                if (count % partial == 0)
                    Console.Write(".");

                try
                {
                    var cmd = conn.CreateCommand();
                    cmd.CommandText = String.Format("SELECT COUNT(*) FROM CajasClientes WHERE ClienteId = {0} AND Numero = {1}", caja.clienteId, caja.numero);
                    int cnt = (int)cmd.ExecuteScalar();
                    if (cnt != 0)
                        continue;

                    cmd.CommandText = GetCajaInsert(caja);
                    cmd.ExecuteNonQuery();

                    cmd = conn.CreateCommand();
                    cmd.CommandText = "SELECT @@IDENTITY";
                    int id = Convert.ToInt32(cmd.ExecuteScalar());
                    caja.id = id;

                    success++;
                }
                catch (Exception ex)
                {
                    erroresCajasDeClientes.Add(new ErroresEnCajasDeClientes
                    {
                        caja = caja,
                        exception = ex
                    });
                }
            }

            Log(String.Format("\nSe insertaron {0} cajas de clientes de {1}. {2} Errores.", success, cajas.Count, erroresCajasDeClientes.Count), true);

        }

        private void CargarDepositos(SqlConnection conn)
        {
            Log("Insertando Depósitos...", true);

            var cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Depositos ON";
            cmd.ExecuteNonQuery();

            int count = 0;

            foreach (var deposito in depositos)
            {
                try
                {
                    cmd.CommandText = String.Format("SELECT COUNT(*) FROM Depositos WHERE Id = {0}", deposito.id);
                    int cnt = (int)cmd.ExecuteScalar();
                    if (cnt != 0)
                        continue;

                    cmd = conn.CreateCommand();
                    cmd.CommandText = GetDepositoInsert(deposito);
                    cmd.ExecuteNonQuery();

                    count++;
                }
                catch (Exception ex)
                {
                    erroresDepositos.Add(new ErroresEnDepositos
                    {
                        deposito = deposito,
                        exception = ex
                    });
                }
            }

            cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Depositos OFF";
            cmd.ExecuteNonQuery();

            Log(String.Format("Se insertaron {0} depositos de {1}. {2} Errores.", count, depositos.Count, erroresDepositos.Count), true);
        }

        private void CargarEstanterias(SqlConnection conn)
        {
            Log("Insertando Estanterías...", true);

            var cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Estanterias ON";
            cmd.ExecuteNonQuery();

            int count = 0;

            foreach (var estanteria in estanterias)
            {
                try
                {
                    cmd.CommandText = String.Format("SELECT COUNT(*) FROM Estanterias WHERE Id = {0}", estanteria.id);
                    int cnt = (int)cmd.ExecuteScalar();
                    if (cnt != 0)
                        continue;

                    cmd = conn.CreateCommand();
                    cmd.CommandText = GetEstanteriaInsert(estanteria);
                    cmd.ExecuteNonQuery();

                    count++;
                }
                catch (Exception ex)
                {
                    erroresEstanterias.Add(new ErroresEnEstanterias
                    {
                        estanteria = estanteria,
                        exception = ex
                    });
                }
            }

            cmd = conn.CreateCommand();
            cmd.CommandText = "SET IDENTITY_INSERT Estanterias OFF";
            cmd.ExecuteNonQuery();

            Log(String.Format("Se insertaron {0} estanterias de {1}. {2} Errores.", count, estanterias.Count, erroresEstanterias.Count), true);
        }

        private void CargarUbicaciones(SqlConnection conn)
        {
            Log("Insertando Ubicaciones...", true);

            int partial = 200;
            int count = 0;
            int success = 0;
            List<int> cajasYaActualizadas = new List<int>();
            List<int> ubicacionesDuplicadas = new List<int>();
            List<SqlUbicacion> sqlUubicaciones = new List<SqlUbicacion>();

            // Leo la base actual
            var cmd = conn.CreateCommand();
            cmd.CommandText = String.Format(@"SELECT u.[Id] as [UbiId]
                                                            ,u.[NumeroCaja] as [UbiNum]
                                                            ,u.[CajaCliente] as [CajaId]
                                                            ,c.[CodigoBarra] as [CajaCod]
                                                      FROM [Ubicaciones] u
                                                      LEFT OUTER JOIN [CajasClientes] c ON u.Id = c.UbicacionId");

            using (var reader = cmd.ExecuteReader())
            {
                while (reader.Read())
                {
                    sqlUubicaciones.Add(new SqlUbicacion
                    {
                        ubiId = reader.GetInt32(0),
                        numCaja = reader.GetInt32(1),
                        cajaId = reader.IsDBNull(2) ? new Nullable<int>() : reader.GetInt32(2),
                        cajaCod = reader.IsDBNull(3) ? null : reader.GetString(3),
                    });
                }
            }

            foreach (var ubiOrigen in ubicaciones)
            {
                count++;
                if (count % partial == 0)
                    Console.Write(".");

                try
                {
                    if (ubicaciones.Count(c => c.numeroCaja == ubiOrigen.numeroCaja) > 1)
                    {
                        if (!ubicacionesDuplicadas.Contains(ubiOrigen.numeroCaja))
                            ubicacionesDuplicadas.Add(ubiOrigen.numeroCaja);
                        else
                            continue;

                        throw new Exception(String.Format("La ubicación {0}: está duplicada.", ubiOrigen.numeroCaja.ToString()));
                    }

                    var ubiDestino = sqlUubicaciones.FirstOrDefault(u => u.numCaja == ubiOrigen.numeroCaja);

                    if (ubiDestino == null)
                    {
                        throw new Exception("No se encontró la ubicación: " + ubiOrigen.numeroCaja.ToString());
                    }

                    int? cajaId = ubiDestino.cajaId;

                    if (String.IsNullOrEmpty(ubiOrigen.codigoBarraCajaCliente) || ubiOrigen.codigoBarraCajaCliente == "0")
                    {
                        // 1) NULL & NULL => Nada
                        if (cajaId == null)
                            continue;

                        // 2.1) NULL & Caja Nueva => Nada
                        else if (ubiDestino.cajaCod.Contains('-'))
                        {
                            throw new Exception(String.Format("La ubicación {0} está vacía en ACCESS pero en la base de SQL indica la caja {1}", ubiDestino.numCaja, ubiDestino.cajaCod));
                        }
                        else
                        {
                            // 2.2 NULL & Caja Vieja => Actualizo la ubicación y la caja con NULL

                            if (!cajasYaActualizadas.Contains(cajaId.Value))
                            {
                                cmd = conn.CreateCommand();
                                cmd.CommandText = GetCajaUpdate(cajaId.Value, null);
                                cmd.ExecuteNonQuery();
                            }

                            cmd = conn.CreateCommand();
                            cmd.CommandText = GetUbicacionUpdate(ubiDestino.ubiId, null);
                            cmd.ExecuteNonQuery();

                            success++;
                        }
                    }

                    if (!String.IsNullOrEmpty(ubiOrigen.codigoBarraCajaCliente) && ubiOrigen.codigoBarraCajaCliente != "0")
                    {
                        if (cajaId == null)
                        {
                            // 3) Caja Vieja & NULL => Actualizo con la Caja Vieja

                            cmd = conn.CreateCommand();
                            cmd.CommandText = "SELECT Id FROM CajasClientes WHERE CodigoBarra = '*" + ubiOrigen.codigoBarraCajaCliente + "*'";
                            cajaId = (int?)cmd.ExecuteScalar();

                            if (!cajaId.HasValue)
                            {
                                // trato de buscar con el nuevo código
                                var caja = cajas.FirstOrDefault(c => c.codigoBarra == String.Format("*{0}*", ubiOrigen.codigoBarraCajaCliente));
                                if (caja != null)
                                {
                                    cmd = conn.CreateCommand();
                                    cmd.CommandText = String.Format("SELECT Id FROM CajasClientes WHERE CodigoBarra = '{0}-{1}'", caja.clienteId, caja.numero);
                                    cajaId = (int?)cmd.ExecuteScalar();
                                }
                            }

                            if (!cajaId.HasValue)
                                throw new Exception("No se encontró la caja *" + ubiOrigen.codigoBarraCajaCliente + "*");

                            cmd = conn.CreateCommand();
                            cmd.CommandText = GetCajaUpdate(cajaId.Value, ubiDestino.ubiId);
                            cmd.ExecuteNonQuery();

                            cajasYaActualizadas.Add(cajaId.Value);

                            cmd = conn.CreateCommand();
                            cmd.CommandText = GetUbicacionUpdate(ubiDestino.ubiId, cajaId);
                            cmd.ExecuteNonQuery();

                            success++;
                        }

                        else if (ubiDestino.cajaCod == String.Format("*{0}*", ubiOrigen.codigoBarraCajaCliente))
                        {
                            // 5) Misma caja => Nada
                            continue;
                        }
                        else if (ubiDestino.cajaCod.Contains('-'))
                        {
                            var caja = cajas.FirstOrDefault(c => c.codigoBarra == String.Format("*{0}*", ubiOrigen.codigoBarraCajaCliente));

                            if (caja == null)
                            {
                                throw new Exception(String.Format("No se encontró la caja *{0}*", ubiOrigen.codigoBarraCajaCliente));
                            }

                            string nuevoCod = String.Format("{0}-{1}", caja.clienteId, caja.numero);

                            // 4) Caja Vieja & Caja Nueva => nada, informo
                            if (ubiDestino.cajaCod != nuevoCod)
                                throw new Exception(String.Format("La ubicación {0} indica la caja {1} pero se encuentra ocupada por la caja {2}", ubiOrigen.numeroCaja, ubiOrigen.codigoBarraCajaCliente, ubiDestino.cajaCod));
                            else
                            {
                                // misma caja, distinto codigo
                                continue;
                            }
                        }
                        else
                        {
                            // 6) Caja Vieja => Otra Caja Vieja
                            // Actualizo la caja actual con null
                            if (!cajasYaActualizadas.Contains(cajaId.Value))
                            {
                                cmd = conn.CreateCommand();
                                cmd.CommandText = GetCajaUpdate(cajaId.Value, null);
                                cmd.ExecuteNonQuery();
                            }

                            // Busco la nueva caja
                            cmd = conn.CreateCommand();
                            cmd.CommandText = "SELECT Id FROM CajasClientes WHERE CodigoBarra = '*" + ubiOrigen.codigoBarraCajaCliente + "*'";
                            cajaId = (int?)cmd.ExecuteScalar();

                            if (!cajaId.HasValue)
                            {
                                // trato de buscar con el nuevo código
                                var caja = cajas.FirstOrDefault(c => c.codigoBarra == String.Format("*{0}*", ubiOrigen.codigoBarraCajaCliente));
                                if (caja != null)
                                {
                                    cmd = conn.CreateCommand();
                                    cmd.CommandText = String.Format("SELECT Id FROM CajasClientes WHERE CodigoBarra = '{0}-{1}'", caja.clienteId, caja.numero);
                                    cajaId = (int?)cmd.ExecuteScalar();
                                }
                            }

                            if (!cajaId.HasValue)
                                throw new Exception("No se encontró la caja *" + ubiOrigen.codigoBarraCajaCliente + "*");

                            // Actualizo la caja y la ubicación
                            cmd = conn.CreateCommand();
                            cmd.CommandText = GetCajaUpdate(cajaId.Value, ubiDestino.ubiId);
                            cmd.ExecuteNonQuery();

                            cajasYaActualizadas.Add(cajaId.Value);

                            cmd = conn.CreateCommand();
                            cmd.CommandText = GetUbicacionUpdate(ubiDestino.ubiId, cajaId);
                            cmd.ExecuteNonQuery();

                            success++;
                        }
                    }
                }
                catch (Exception ex)
                {
                    erroresUbicaciones.Add(new ErroresEnUbicaciones
                    {
                        ubicacion = ubiOrigen,
                        exception = ex
                    });
                }
            }

            Log(String.Format("\nSe actualizaron {0} ubicaciones de {1}. {2} Errores.", success, ubicaciones.Count, erroresUbicaciones.Count), true);
        }

        // INSERTS

        private string GetClienteInsert(Cliente cliente)
        {
            var commandText = String.Format(
@"INSERT INTO [Aga].[dbo].[Clientes]
           ([Id]
           ,[Nombre]
           ,[Cuit]
           ,[Direccion]
           ,[Localidad]
           ,[Provincia]
           ,[CodigoPostal]
           ,[Telefonos]
           ,[Fax]
           ,[Web]
           ,[Email]
           ,[CreationDate]
           ,[CreationUser]
           ,[Tipo]
           ,[ExId]
           ,[Responsable]
           ,[EmailResponsable])
     VALUES
           ({0},'{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}'
           ,'{10}','{11}','{12}',{13},{14},'{15}','{16}')",
        cliente.codigo,
        cliente.nombre,
        cliente.cuit,
        cliente.direccion,
        cliente.localidad,
        cliente.provincia,
        cliente.cp,
        cliente.telefonos,
        cliente.fax,
        cliente.web,
        cliente.email1 ?? cliente.email2,
        DateTime.Now.ToShortDateString(),
        "admin",
        1,
        cliente.codigo,
        cliente.responsable,
        cliente.emailResponsable);

            return commandText;
        }

        private string GetCajaInsert(CajaDeCliente caja)
        {
            var commandText = String.Format(
    @"INSERT INTO [Aga].[dbo].[CajasClientes]
           ([ClienteId]
           ,[Numero]
           ,[CodigoBarra]
           ,[CreationDate]
           ,[CreationUser]
           ,[Observaciones])
     VALUES
           ({0},{1},'{2}','{3}','{4}','{5}')",
            caja.clienteId,
            caja.numero,
            caja.codigoBarra,
            DateTime.Now.ToShortDateString(),
            "admin",
            caja.observaciones);

            return commandText;
        }

        private string GetDepositoInsert(Deposito deposito)
        {
            var commandText = String.Format(
                @"INSERT INTO [Aga].[dbo].[Depositos]
                       ([Id]
                       ,[Nombre]
                       ,[Descripcion]
                       ,[CreationDate]
                       ,[CreationUser]
                       ,[UbicacionInicial]
                       ,[Numero])
                 VALUES
                       ({0}
                       ,'{1}'
                       ,'{2}'
                       ,'{3}'
                       ,'{4}'
                       ,{5}
                       ,{6})",
                        deposito.id,
                        deposito.nombre,
                        deposito.descripcion,
                        DateTime.Now.ToShortDateString(),
                        "admin",
                        1,
                        deposito.numero);

            return commandText;
        }

        private string GetEstanteriaInsert(Estanteria estanteria)
        {
            int depositoId = depositos.Where(d => d.numero.Equals(estanteria.depositoId)).Select(d => d.id).Single();

            var commandText = String.Format(
                @"INSERT INTO [Aga].[dbo].[Estanterias]
                       ([Id]
                       ,[DepositoId]
                       ,[Numero]
                       ,[Sector]
                       ,[Horizontal]
                       ,[Vertical]
                       ,[Fondo]
                       ,[CreationDate]
                       ,[CreationUser])
                 VALUES
                       ({0}
                       ,{1}
                       ,{2}
                       ,{3}
                       ,{4}
                       ,{5}
                       ,{6}
                       ,'{7}'
                       ,'{8}')",
                        estanteria.id,
                        depositoId,
                        estanteria.numero,
                        estanteria.sector,
                        estanteria.horizontal,
                        estanteria.vertical,
                        estanteria.fondo,
                        DateTime.Now.ToShortDateString(),
                        "admin");

            return commandText;
        }

        private string GetUbicacionInsert(Ubicacion ubi)
        {
            //int depositoId = estanteria.depositoId.Equals(1) ? 1 : estanteria.depositoId.Equals(2) ? 8 : 9;

            var commandText = String.Format(
                @"INSERT INTO [Aga].[dbo].[Ubicaciones]
                       ([NumeroCaja]
                       ,[EstanteriaId]
                       ,[Sector]
                       ,[Cuadrante]
                       ,[Horizontal]
                       ,[Vertical]
                       ,[Fondo]
                       ,[Estado]
                       ,[CodigoBarra]
                       ,[CajaCliente]
                       ,[CreationDate]
                       ,[CreationUser])
                 VALUES
                       ({0}
                       ,{1}
                       ,{2}
                       ,{3}
                       ,{4}
                       ,{5}
                       ,{6}
                       ,'{7}'
                       ,'{8}'
                       ,{9}
                       ,'{10}'
                       ,'{11}')",
                        ubi.numeroCaja,
                        BuscarEstanteriaId(ubi.estanteriaId, ubi.sector),
                        ubi.sector,
                        ubi.cuadrante,
                        ubi.horizontal,
                        ubi.vertical,
                        ubi.fondo,
                        ubi.estado,
                        ubi.codigoBarra,
                        ubi.cajaClienteId != null ? ubi.cajaClienteId.ToString() : "NULL",
                        DateTime.Now.ToShortDateString(),
                        "admin");

            return commandText;
        }

        private string GetCajaUpdate(int cajaId, int? ubiId)
        {
            var commandText = String.Format(
                                    @"UPDATE [Aga].[dbo].[CajasClientes]
                                      SET [UbicacionId] = {0}, [Estado] = '{2}'
                                      WHERE [Id] = {1}",
                                    ubiId.HasValue ? ubiId.Value.ToString() : "NULL",
                                    cajaId,
                                    ubiId.HasValue ? "EnGuarda" : "Creada");

            return commandText;
        }

        private string GetUbicacionUpdate(int ubiId, int? cajaId)
        {
            var commandText = String.Format(
                        @"UPDATE [Aga].[dbo].[Ubicaciones]
                          SET [CajaCliente] = {1}
                          WHERE [Id] = {0}",
                        ubiId,
                        cajaId.HasValue ? cajaId.Value.ToString() : "NULL");

            return commandText;
        }

        private List<CajaDeCliente> BuscarCajaId(string cajaCliente)
        {
            string codBarra = String.Format("*{0}*", cajaCliente);

            return cajas.Where(c => c.codigoBarra == codBarra).ToList();
        }

        private int BuscarEstanteriaId(int numero, int sector)
        {
            return estanterias.Where(e => e.numero.Equals(numero) && e.sector.Equals(sector)).Select(e => e.id).Single();
        }

        private void Log(string message, bool verbose)
        {
            if (verbose)
            {
                Console.WriteLine(message);
            }
            else
            {
                logger.WriteLine(message);
                logger.Flush();
            }
        }

        private void LogErrors()
        {
            Log("NUMERO;TABLA;CODIGO;NOMBRE;ERROR", false);
            int count = 0;
            foreach (var e in erroresClientes)
            {
                count++;
                Log(String.Format("{0};Clientes;{1};{2};{3}", count, e.cliente.codigo, e.cliente.nombre, e.exception.Message), false);
            }
            Log(";;;;;;", false);
            Log("NUMERO;TABLA;CLIENTE;NUMERO;UBICACION;ERROR", false);
            foreach (var e in erroresCajasDeClientes)
            {
                count++;
                Log(String.Format("{0};CajasDeClientes;{1};{2};{3};{4}", count, e.caja.clienteId, e.caja.numero, e.caja.ubicacionId ?? 0, e.caja.numeroUbicacion, e.exception.Message), false);
            }

            Log(";;;;;;", false);
            Log("NUMERO;TABLA;NUMERO;NOMBRE;ERROR", false);
            foreach (var e in erroresDepositos)
            {
                count++;
                Log(String.Format("{0};Depósitos;{1};{2};{3}", count, e.deposito.numero, e.deposito.nombre, e.exception.Message), false);
            }

            Log(";;;;;;", false);
            Log("NUMERO;TABLA;NUMERO;ERROR", false);
            foreach (var e in erroresEstanterias)
            {
                count++;
                Log(String.Format("{0};Estanterías;{1};{2}", count, e.estanteria.numero, e.exception.Message), false);
            }

            Log(";;;;;;", false);
            Log("NUMERO;TABLE;ESTANTERIA;UBICACION;ERROR", false);
            foreach (var e in erroresUbicaciones)
            {
                count++;
                Log(String.Format("{0};Estanterías;{1};{2};{3}", count, e.ubicacion.estanteriaId, e.ubicacion.numeroCaja, e.exception.Message), false);
            }

        }

        private void InformarCajasSinUbicar()
        {
            var errores = from c in cajas
                          where c.ubicacionId != null &&
                                !c.ubicacionId.HasValue &&
                                c.numeroUbicacion != null
                          select new ErroresEnCajasDeClientes
                          {
                              caja = c,
                              exception = new Exception(String.Format("No se ubicó la caja {0} en la ubicación {1}", c.numero, c.numeroUbicacion))
                          };

            erroresCajasDeClientes.AddRange(errores);
        }
    }

    class Cliente
    {
        public int codigo;
        public string nombre;
        public string responsable;
        public string emailResponsable;
        public string telefonos;
        public string fax;
        public string direccion;
        public string cp;
        public string localidad;
        public string provincia;
        public string cuit;
        public string web;
        public string email1;
        public string email2;
    }
    class CajaDeCliente
    {
        public int? id;
        public int clienteId;
        public int numero;
        public string codigoBarra;
        public int? numeroUbicacion;
        public int? ubicacionId;
        public string observaciones;
    }
    class Deposito
    {
        public int id;
        public int numero;
        public string nombre;
        public string descripcion;
    }
    class Estanteria
    {
        public int id;
        public int depositoId;
        public int numero;
        public int sector;
        public int horizontal;
        public int vertical;
        public int fondo;
    }
    class Ubicacion
    {
        public int numeroCaja;
        public int estanteriaId;
        public int sector;
        public int cuadrante;
        public int horizontal;
        public int vertical;
        public int fondo;
        public int? cajaClienteId;
        public string codigoBarraCajaCliente;
        public string estado;
        public string codigoBarra;
    }

    struct ErroresEnClientes
    {
        public Cliente cliente;
        public Exception exception;
    }
    struct ErroresEnCajasDeClientes
    {
        public CajaDeCliente caja;
        public Exception exception;
    }
    struct ErroresEnDepositos
    {
        public Deposito deposito;
        public Exception exception;
    }
    struct ErroresEnEstanterias
    {
        public Estanteria estanteria;
        public Exception exception;
    }
    struct ErroresEnUbicaciones
    {
        public Ubicacion ubicacion;
        public Exception exception;
    }

    public class SqlUbicacion
    {
        public int ubiId;
        public int numCaja;
        public int? cajaId;
        public string cajaCod;
    }
}
